﻿
//	------------------------------------------------------------------------------
//                                       _                          
//              _ __ ___   ___ _ __ ___ | |__  _ __ __ _ _ __   ___ 
//             | '_ ` _ \ / _ \ '_ ` _ \| '_ \| '__/ _` | '_ \ / _ \
//             | | | | | |  __/ | | | | | |_) | | | (_| | | | |  __/
//             |_| |_| |_|\___|_| |_| |_|_.__/|_|  \__,_|_| |_|\___|
//                                                     
//	------------------------------------------------------------------------------

#region - License -
//
//	------------------------------------------------------------------------------                                                   
//	         Copyright (c) 2010 Peter Vyvey (peter.vyvey@chiliware.be)
//	------------------------------------------------------------------------------
//
//
//	This file is part of CHILIWARE MEMBRANE.
//
//	CHILIWARE MEMBRANE is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	CHILIWARE MEMBRANE is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public License
//	along with CHILIWARE MEMBRANE.  If not, see <http://www.gnu.org/licenses/>.
//
//
#endregion

#region - Changes -

//	peter.vyvey@chiliware.be     2010-08-22      Created.

#endregion

#region - Using -

using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;

#endregion

namespace Chiliware.Membrane.Extension
{
	#region - SerializerExtension -

	/// <summary>
	/// Extension method to handle serialization and deserialization.
	/// </summary>
	public static class SerializerExtension
	{

#if (!SILVERLIGHT)

		#region - Constants -

		/// <summary>
		/// The default encoding.
		/// </summary>
		public static readonly Encoding DEFAULT_ENCODING = Encoding.Unicode;

		#endregion

		#region - SerializeToXml -

		/// <summary>
		/// Serializes an object to an XML serialized object using the DataContractSerializer
		/// </summary>
		/// <param name="instance">Instance of an object</param>
		/// <returns>An XML document containing the serialized object</returns>
		public static XmlDocument SerializeToXml<T>(this T instance)
		{
			NetDataContractSerializer serializer = new NetDataContractSerializer();

			return SerializeToXml(instance, serializer);
		}

		/// <summary>
		/// Serializes an object to an XML serialized object using the DataContractSerializer
		/// </summary>
		/// <param name="instance">Instance of an object</param>
		/// <param name="serializer">The NetDataContractSerializer.</param>
		/// <returns>An XML document containing the serialized object</returns>
		/// <exception cref="System.ArgumentNullException">Thrown if the instance is null.</exception>
		private static XmlDocument SerializeToXml<T>(this T instance, NetDataContractSerializer serializer)
		{
			instance.CatchNullArgument("instance");
			serializer.CatchNullArgument("serializer");

			StringBuilder builder = new StringBuilder();
			using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(builder, new XmlWriterSettings() { Indent = true }))
			{
				serializer.WriteObject(writer, instance);
			}

			XmlDocument xmlDocument = new XmlDocument();
			xmlDocument.LoadXml(builder.ToString());

			return xmlDocument;
		}

		#endregion

		#region - DeserializeFromXml -

		/// <summary>
		/// Deserializes an object contained in an XML document
		/// </summary>
		/// <param name="xmlDocument">The XML document with the serialzed object.</param>
		/// <returns>A deserialized object</returns>
		public static T DeserializeFromXml<T>(this XmlDocument xmlDocument)
		{
			NetDataContractSerializer serializer = new NetDataContractSerializer();
			return DeserializeFromXml<T>(xmlDocument, SerializerExtension.DEFAULT_ENCODING);
		}

		/// <summary>
		/// Deserializes an object contained in an XML document
		/// </summary>
		/// <param name="xmlDocument">The XML document with the serialzed object.</param>
		/// <param name="encoding">The encoding of the XML document.</param>
		/// <returns>A deserialized object</returns>
		public static T DeserializeFromXml<T>(this XmlDocument xmlDocument, Encoding encoding)
		{
			NetDataContractSerializer serializer = new NetDataContractSerializer();
			return DeserializeFromXml<T>(xmlDocument, encoding, serializer);
		}

		/// <summary>
		/// Deserializes an object contained in an XML document
		/// </summary>
		/// <param name="xmlDocument">The XML document with the serialzed object.</param>
		/// <param name="encoding">The encoding of the XML document.</param>
		/// <param name="serializer">The NetDataContractSerializer.</param>
		/// <returns>A deserialized object</returns>
		private static T DeserializeFromXml<T>(this XmlDocument xmlDocument, Encoding encoding, NetDataContractSerializer serializer)
		{
			xmlDocument.CatchNullArgument("xmlDocument");
			encoding.CatchNullArgument("encoding");
			serializer.CatchNullArgument("serializer");

			object instance = null;

			using (MemoryStream memoryStream = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(xmlDocument.InnerXml)))
			{
				using (StreamReader stream = new StreamReader(memoryStream, encoding))
				{
					using (XmlReader reader = XmlReader.Create(stream))
					{
						instance = (T)serializer.ReadObject(reader);
					}
				}
			}

			return (T)instance;
		}

		#endregion

#endif

		#region - Clone -

		/// <summary>
		/// Clones the instance of an object.
		/// </summary>
		/// <param name="instance">Instance of an object.</param>
		/// <returns>An clone of the instance parameter.</returns>
		public static T Clone<T>(this T instance)
		{
#if (SILVERLIGHT)
			T clone = default(T);
			DataContractSerializer serializer = new DataContractSerializer(typeof(T));

			using (MemoryStream stream = new MemoryStream())
			{
				serializer.WriteObject(stream, instance);
				stream.Position = 0;
				clone = (T)serializer.ReadObject(stream);
			}

			return clone;
#else
			return instance.SerializeToXml<T>().DeserializeFromXml<T>();
#endif
		}

		#endregion

	}

	#endregion
}
